#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "drawables/emfgrid.h"
#include <QSqlQuery>
#include <QProgressDialog>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    rightPanel = 0;
    glWidget = 0;
    adapter = 0;
    polygonDialog = 0;
    configDialog = 0;
    _mode = MAP;



    _initSettings();

    bool config = true;
    if(settings->isEmpty())
       config = _initDbConfiguration();

    if(config)
    {
        _initDbConnection();
        _initPolygonDialog();
    }

    if(!dbconnect->getDb().isOpen())
    {
        this->setWindowTitle("Connection disactive");
    }

    _setIcon("./favicon.ico");
    _initEventHandlers();

    _initToolBarMap();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::_showDrawables(int selectedId)
{

    glWidget->clear();

    if(_mode == MAP)
    {
        glWidget->switchToLinearCoords();

        QSharedPointer<ElementIterator> loopIterator = polygonData->createLoopIterator();
         _addDrawables(loopIterator.data());

        QSharedPointer<ElementIterator> picketIterator = polygonData->createPicketIterator();
        _addDrawables(picketIterator.data());

        glWidget->autoScale();
    }
    else
    {
        glWidget->switchToLogarithmicCoords();
        QSharedPointer<ElementIterator> emfIterator = polygonData->createEmfIterator();
        _addDrawables(emfIterator.data());
    }
    glWidget->selectObject(selectedId);
    glWidget->updateGL();
}

int MainWindow::_getTreeSelectedItem(QModelIndex index)
{
    QVariant id = index.data(Qt::UserRole+1);
    return id.toInt();
}

void MainWindow::onTreeViewDoubleClick(QModelIndex index)
{
    int id = _getTreeSelectedItem(index);    
    if(_mode != MAP)
    {
        _mode = MAP;
        _switchGlWidgetToMap();
    }
    _showDrawables(id);
    _showInfoDocks(id);
}

void MainWindow::_showInfoDocks(int selectedId)
{
    _initRightPanel();

    QLayout *dockLayout = polygonData->getInfoDock(selectedId);
    if(dockLayout)
    {        
        rightPanel->addLayout(dockLayout);
        rightPanel->addStretch();
    }
}

void MainWindow::_initDbConnection()
{
    //Create object who can create db connection
    dbconnect = DbConnection::instance();
    QMessageBox msgBox;
    if(!dbconnect->setupConnection(settings))
    {
        msgBox.setText(dbconnect->getDb().lastError().text());
        msgBox.exec();
        return;
    }
}

void MainWindow::_initGlWidget()
{
    //GL Window
    if(ui->openGlLayout)
    {
        _clearLayout(ui->openGlLayout);
    }
    glWidget = new GlMapWidget();
    EmfGrid *grid = new EmfGrid();
    grid->setPolygonData(polygonData);
    glWidget->setEmfGrid(grid);

    ui->openGlLayout->addWidget(glWidget);
    connect(glWidget, SIGNAL(selectedItem(int)), this, SLOT(onGlWidgetClick(int)));
}

void MainWindow::_initSettings()
{
    //Create object who can save dcconnection settings
    settings = Settings::instance();
    settings->load();
}

void MainWindow::_initEventHandlers()
{
    connect(ui->leftPanel, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onTreeViewDoubleClick(QModelIndex)));
    connect(ui->leftPanel,
            SIGNAL(customContextMenuRequested(const QPoint &)),
            this,
            SLOT(contextMenu(const QPoint &)));
    connect(ui->actionConfigure_connection,
            SIGNAL(activated()),
            this,
            SLOT(onMenuConfigConnectionActivate()));
    connect(ui->actionReconnect,
            SIGNAL(activated()),
            this,
            SLOT(onMenuReconnectActivate()));
    connect(ui->actionSelect,
            SIGNAL(activated()),
            this,
            SLOT(onMenuDatasetSelectActivate()));
    connect(ui->actionIncreaseXScale,
            SIGNAL(activated()),
            this,
            SLOT(onIncreaseXScale()));
    connect(ui->actionDecreaseXScale,
            SIGNAL(activated()),
            this,
            SLOT(onDecreaseXScale()));
    connect(ui->actionIncreaseYScale,
            SIGNAL(activated()),
            this,
            SLOT(onIncreaseYScale()));
    connect(ui->actionDecreaseYScale,
            SIGNAL(activated()),
            this,
            SLOT(onDecreaseYScale()));
    connect(ui->actionOneToOne,
            SIGNAL(activated()),
            this,
            SLOT(onOneToOne()));
    connect(ui->actionDecorate,
            SIGNAL(activated()),
            this,
            SLOT(onDecorate()));
    connect(ui->actionAverage,
            SIGNAL(activated()),
            this,
            SLOT(onAverage()));

}

void MainWindow::_initRightPanel()
{
    if(rightPanel)
    {
        _clearLayout(rightPanel);
        delete rightPanel;
    }
    rightPanel = new QVBoxLayout();
    ui->rightScrollAreaWidgetContents->setLayout(rightPanel);
}

void MainWindow::_clearLayout(QLayout *layout)
{
    while (QLayoutItem* item = layout->takeAt(0))
    {
       if (QWidget* widget = item->widget())
            delete widget;
       else if (QLayout* childLayout = item->layout())
           _clearLayout(childLayout);
       delete item;
    }
}

void MainWindow::_initLeftPanel()
{
    adapter = new TreeViewAdapter();
    adapter->addFromIterator("Loops", polygonData->createLoopIterator().data());
    adapter->addFromIterator("Pickets", polygonData->createPicketIterator().data());

    ui->leftPanel->setModel(adapter);
    ui->leftPanel->expandAll();
    //for context menu appear
    ui->leftPanel->setContextMenuPolicy(Qt::CustomContextMenu);
}

void MainWindow::_initToolBarMap()
{    
    timeEdit = new QLineEdit(QString::number(0));
    ui->toolBarMap->insertWidget(ui->actionDecorate, new QLabel("time: "));
    ui->toolBarMap->insertWidget(ui->actionDecorate, timeEdit);
}

void MainWindow::_addDrawables(ElementIterator *iterator)
{
    for(iterator->begin(); !iterator->isFinished(); iterator->next())
    {
        int id = iterator->currentKey();
        QMap<QString, Drawable *> map = polygonData->getDrawable(id);
        if(!map.empty())
            glWidget->addDrawable(map.begin().value());
    }
}

void MainWindow::_addInfodocks(QSharedPointer<QMap<int, QPointF> > emfMap)
{
    _clearLayout(rightPanel);
    for(QMap<int, QPointF>::iterator i=emfMap->begin(); i!=emfMap->end(); ++i)
    {
        int id = i.key();
        QLayout *docks = polygonData->getInfoDock(id, &i.value());
        if(docks)
        {
            rightPanel->addLayout(docks);
        }
    }
    rightPanel->addStretch();
}



void MainWindow::onGlWidgetClick(int id)
{
    if(id > -1)
    {
        _showInfoDocks(id);
    }
}

void MainWindow::contextMenu(const QPoint &point)
{
    QModelIndex index = ui->leftPanel->indexAt(point);
    QVariant indexData = index.data(Qt::UserRole+1);
    if(indexData.isValid())
    {
        QPoint globalPos = ui->leftPanel->mapToGlobal(point);
        // for QAbstractScrollArea and derived classes you would use:
        // QPoint globalPos = myWidget->viewport()->mapToGlobal(pos);
        QMenu myMenu;
        myMenu.addAction("Show Emf");
        QAction* selectedItem = myMenu.exec(globalPos);
        if (selectedItem)
        {

            polygonData->loadEmf(indexData.toInt());


            bool needAutoScale = _mode != EMF;
            if(_mode != EMF)
            {                
                _mode = EMF;
                _switchGlWidgetToEmf();
            }
            _showDrawables(-1);
            if(needAutoScale)
                glWidget->autoScale();
        }
    }
}

void MainWindow::_initPolygonDialog()
{
    if(dbconnect->setupConnection(settings))
    {
        polygonDialog = new PolygonDialog();
        polygonDialog->loadPolygons();
        if( polygonDialog->exec() == QDialog::Accepted )
        {
            QString idPolygon = polygonDialog->getPolygon();
            _loadData(idPolygon);
            _initDataViews();
            _idPolygon = idPolygon;
        }
    }
}

void MainWindow::_loadData(QString idPolygon)
{
    polygonData = PolygonData::instance();
    polygonData->clear();
    QTime time;
    time.start();
    polygonData->load(idPolygon);
    qDebug("Pickets time elapsed: %d ms", time.elapsed());
}

bool MainWindow::_initDbConfiguration()
{
    configDialog = new ConfigurationDialog();
    configDialog->setSettings(settings);
    configDialog->setDbConnection(dbconnect);
    if(configDialog->exec() == QDialog::Accepted)
    {
        return true;
    }
    return false;
}

void MainWindow::onMenuConfigConnectionActivate()
{
    if(_initDbConfiguration())
    {
        _initDbConnection();
        _initPolygonDialog();
    }
}

void MainWindow::onMenuDatasetSelectActivate()
{
    _initPolygonDialog();
}

void MainWindow::onMenuReconnectActivate()
{
    _initSettings();

    bool config = true;
    if(settings->isEmpty())
       config = _initDbConfiguration();

    if(config)
    {
        _initDbConnection();
        _initPolygonDialog();
    }
}

void MainWindow::_initDataViews()
{
    _initRightPanel();
    _initGlWidget();
    _initLeftPanel();
}

void MainWindow::_switchGlWidgetToEmf()
{
    //GL Window
    if(ui->openGlLayout)
    {
        _clearLayout(ui->openGlLayout);
    }
    glWidget = new GlEmfWidget();

    if(dynamic_cast<GlEmfWidget*>(glWidget))
    {
    connect(glWidget,
            SIGNAL(sendEmfInfo(QSharedPointer<QMap<int, QPointF> >)),
            this,
            SLOT(onEmfSelected(QSharedPointer<QMap<int, QPointF> >)));
    }
    ui->openGlLayout->addWidget(glWidget);
}

void MainWindow::_switchGlWidgetToMap()
{
    _initGlWidget();
}

void MainWindow::_setIcon(QString filepath)
{
    QIcon icon = QIcon(filepath);
    this->setWindowIcon(icon);
}


void MainWindow::onEmfSelected(QSharedPointer<QMap<int, QPointF> > emfMap)
{  
    _addInfodocks(emfMap);
}

void MainWindow::onIncreaseXScale()
{
    glWidget->increaseXScale();
}

void MainWindow::onDecreaseXScale()
{
    glWidget->decreaseXScale();
}

void MainWindow::onIncreaseYScale()
{
    glWidget->increaseYScale();
}

void MainWindow::onDecreaseYScale()
{
    glWidget->decreaseYScale();
}

void MainWindow::onOneToOne()
{
    glWidget->oneToOne();
}

void MainWindow::onDecorate()
{
    QTime t;
    t.start();

    QProgressDialog progressBarDialog;
    progressBarDialog.setLabelText("Loading...");
    progressBarDialog.setRange(0, 101);
    progressBarDialog.setModal(true);
    progressBarDialog.setCancelButton(0);

    QString time = timeEdit->text();

    int picketsCount = polygonData->getPicketsCount();
    int picketNumber = 0;

    QSharedPointer<ElementIterator> picketIterator = polygonData->createPicketIterator();
    for(picketIterator->begin(); !picketIterator->isFinished(); picketIterator->next())
    {
        int id = picketIterator->currentKey();
        polygonData->loadEmfByTime(id, time);

        picketNumber++;
        qApp->processEvents();
        progressBarDialog.setValue((100 * picketNumber)/picketsCount);
    }    

    qApp->processEvents();
    progressBarDialog.setValue(100);
    glWidget->getEmfGrid()->recalculateColors(&progressBarDialog);

    qApp->processEvents();
    progressBarDialog.close();

    qDebug("Decorate time: %d ms", t.elapsed());
    glWidget->updateGL();
}

void MainWindow::onAverage()
{
    QProgressDialog progressBarDialog;
    progressBarDialog.setLabelText("Loading...");
    progressBarDialog.setRange(0, 101);
    progressBarDialog.setModal(true);
    progressBarDialog.setCancelButton(0);

    progressBarDialog.setValue(0);
    qApp->processEvents();

    polygonData->loadAverageEmf(&progressBarDialog);
    qApp->processEvents();
    progressBarDialog.close();

    bool needAutoScale = _mode != EMF;
    if(_mode != EMF)
    {
        _mode = EMF;
        _switchGlWidgetToEmf();
    }
    _showDrawables(-1);
    if(needAutoScale)
        glWidget->autoScale();

    QSharedPointer<ElementIterator> emfIterator = polygonData->createEmfIterator();
    _addDrawables(emfIterator.data());
}

